package com.base.cn.platform.os.service.manage.function;

import com.base.cn.platform.os.common.constants.CacheConstants;
import com.base.cn.platform.os.common.j2cache.CustomCacheChannel;
import com.base.cn.platform.os.common.j2cache.J2CacheRegion;
import com.base.cn.platform.os.common.mybatis.BaseBiz;
import com.base.cn.platform.os.common.utils.DataUtil;
import com.base.cn.platform.os.common.utils.ObjectUtils;
import com.base.cn.platform.os.common.utils.StringUtils;
import com.base.cn.platform.os.common.utils.result.ResultUtil;
import com.base.cn.platform.os.dao.manage.function.SysFunctionDao;
import com.base.cn.platform.os.entity.manage.function.SysFunction;
import com.base.cn.platform.os.entity.manage.function.SysFunctionCondition;
import com.base.cn.platform.os.entity.manage.group.SysGroupFunction;
import com.base.cn.platform.os.entity.manage.join.SysRoleFunction;
import com.base.cn.platform.os.entity.manage.role.SysRole;
import com.base.cn.platform.os.entity.manage.user.SysUserFunction;
import com.base.cn.platform.os.service.manage.group.SysGroupFunctionBiz;
import com.base.cn.platform.os.service.manage.join.SysRoleFunctionBiz;
import com.base.cn.platform.os.service.manage.join.SysUserRoleBiz;
import com.base.cn.platform.os.service.manage.user.SysUserFunctionBiz;
import com.base.cn.platform.os.service.manage.work.SysUserWorkBenchBiz;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 权限资源业务类
 *
 * @author s.li
 * @create 2018-02-05 16:35
 */
@Service
public class SysFunctionBiz extends BaseBiz<SysFunction,SysFunctionDao> {

    @Autowired
    private SysUserRoleBiz sysUserRoleBiz;
    @Autowired
    private SysRoleFunctionBiz sysRoleFunctionBiz;
    @Autowired
    private SysUserWorkBenchBiz sysUserWorkBenchBiz;
    @Autowired
    private SysGroupFunctionBiz sysGroupFunctionBiz;
    @Autowired
    private SysUserFunctionBiz sysUserFunctionBiz;
    @Autowired
    private CustomCacheChannel customCacheChannel;

    /**
     * 获取用户操作的页面的右则的权限列表
     * @param userId 用户ID
     * @param functionId 权限ID
     * @return List<SysFunction> 权限列表
     */
    public List<SysFunction> findUserPageRightFunctionList(BigDecimal userId,BigDecimal functionId){
        if(ObjectUtils.isNotEmpty(userId) && ObjectUtils.isNotEmpty(functionId)){
            //获取用户所有的权限列表
            List<SysFunction> sysFunctionList = this.findUserFunctionList(userId);
            if(ObjectUtils.isNotEmpty(sysFunctionList)){
                Map<BigDecimal,List<SysFunction>> sysFunctionListMap = sysFunctionList.stream().collect(Collectors.groupingBy(e->e.getParentId()));
                List<SysFunction> rightFunctionList = sysFunctionListMap.get(functionId);
                if(ObjectUtils.isNotEmpty(rightFunctionList)){
                    List<SysFunction> _rightFunctionList = new ArrayList<>();
                    rightFunctionList.stream().forEach(e->{
                        if(e.getFunctionType().intValue()==1){//只获取菜单类型的权限
                            _rightFunctionList.add(e);
                        }
                    });
                    return _rightFunctionList;
                }
            }
        }
        return null;
    }

    /**
     * 删除权限
     * @param ids 要删除的权限ID
     * @return Map<String,Object>
     */
    @Transactional(rollbackFor = IllegalArgumentException.class )
    public Map<String,Object> deleteSysFunction(String ids){
        //删除权限
        this.deleteWhereSql(" id in ("+ids+")");
        //删除角色与权限关联的
        sysRoleFunctionBiz.deleteWhereSql(" functionId in ("+ids+")");
        //删除工作台关联的权限数据
        sysUserWorkBenchBiz.deleteWhereSql(" functionId in ("+ids+")");
        customCacheChannel.evict(J2CacheRegion.SEVEN_DAY_REGION.getKey(),CacheConstants.ALL_FUNCTION_LIST_KEY);
        return ResultUtil.SUCCESS("权限删除成功");
    }

    /**
     * 保存资源权限数据
     * @param sysFunction 资源权限对象内容
     * @return 返回保存后的资源权限对象
     */
    @Transactional(rollbackFor = IllegalArgumentException.class )
    public SysFunction saveSysFunction(SysFunction sysFunction){
        if(!DataUtil.idIsNotNull(sysFunction.getId())){
            this.save(sysFunction);
        }else{
            //未修改前的权限
            SysFunction _sysFunction = this.findById(sysFunction.getId());
            //如果显示工作状态修改了，那要去删除工作台表中的数据
            if(_sysFunction.getShowIndex().intValue()==2 && sysFunction.getShowIndex().intValue()==1){
                //执行删除
                sysUserWorkBenchBiz.deleteWhereSql(" functionId="+sysFunction.getId());
                sysFunction.setWorkType(0);
            }
            this.updateById(sysFunction,null);
        }
        customCacheChannel.evict(J2CacheRegion.SEVEN_DAY_REGION.getKey(),CacheConstants.ALL_FUNCTION_LIST_KEY);
        return sysFunction;
    }

    /**
     * 通过权限ID串，查询权限Map
     * @param functionIds 权限ID串
     * @return Map<BigDecimal,SysFunction>
     */
    public Map<BigDecimal,SysFunction> findSysFunctionMapByIds(String functionIds){
        if(StringUtils.isNotEmpty(functionIds)){
            List<SysFunction> sysFunctionList = this.findSysFunctionListByIds(functionIds);
            if(ObjectUtils.isNotEmpty(sysFunctionList)){
                return sysFunctionList.stream().collect(Collectors.toMap(e->e.getId(),e->e));
            }
        }
        return null;
    }

    /**
     * 通过资源ID串查询资源数据
     * @param functionIds 资源权限ID串
     * @return 资源权限列表
     */
    public List<SysFunction> findSysFunctionListByIds(String functionIds){
        SysFunctionCondition condition = new SysFunctionCondition();
        condition.setFunctionIds(functionIds);
        return findSysFunctionList(condition);
    }

    /**
     * 获取系统所有的权限
     * @return List<SysFunction> 权限列表
     */
    public List<SysFunction> findAllCacheSysFunctionList(){
        List<SysFunction>  sysFunctionList = (List<SysFunction>)customCacheChannel.get(J2CacheRegion.SEVEN_DAY_REGION.getKey(),CacheConstants.ALL_FUNCTION_LIST_KEY).getValue();
        if(ObjectUtils.isEmpty(sysFunctionList)){
            sysFunctionList = this.findSysFunctionList(null);
            if(ObjectUtils.isNotEmpty(sysFunctionList)){
                customCacheChannel.set(J2CacheRegion.SEVEN_DAY_REGION.getKey(),CacheConstants.ALL_FUNCTION_LIST_KEY,sysFunctionList);
            }
        }
        sysFunctionList.forEach(e->e.setHasFunction(false));
        return sysFunctionList;
    }

    /**
     * 查询权限列表
     * @param sysFunctionCondition 查询条件
     * @return 资源权限列表
     */
    public List<SysFunction> findSysFunctionList(SysFunctionCondition sysFunctionCondition){
        StringBuilder whereSql= new StringBuilder(" 1=1");
        if(ObjectUtils.isNotEmpty(sysFunctionCondition)){
            if(ObjectUtils.isNotEmpty(sysFunctionCondition.getParentId())){
                whereSql .append(" and parentId = ").append(sysFunctionCondition.getParentId().toString());
            }
            if(StringUtils.isNotEmpty(sysFunctionCondition.getFunctionIds())){
                whereSql .append( " and id in (").append(sysFunctionCondition.getFunctionIds()).append(")");
            }
            if(sysFunctionCondition.isUrlNotNull()==true){
                whereSql .append(" and functionUrl!='' and functionUrl is not null");
            }
            if(StringUtils.isNotEmpty(sysFunctionCondition.getNotFunctionIds())){
                whereSql .append(" and id not in(").append(sysFunctionCondition.getNotFunctionIds()).append(")");
            }
        }
        whereSql.append(" order by sort asc");
        List<SysFunction> sysFunctionList = this.find(whereSql.toString(),null,null);
        return sysFunctionList;
    }

    /**
     * 获取管理员用户的权限列表（分层，3层）
     * @param userId 用户ID
     * @return  List<SysFunction>
     */
    public List<SysFunction> findLayeredUserFunctionList(BigDecimal userId){
        List<SysFunction> sysFunctionList = this.findUserFunctionList(userId);
        return scaleFunctionList(sysFunctionList);
    }

    /**
     * 查询所有的权限（分层，3层）
     * @return List<SysFunction>
     */
    public List<SysFunction> findAllFunctionList(){
        List<SysFunction> sysFunctionList = this.findSysFunctionList(null);
        return this.scaleFunctionList(sysFunctionList);
    }

    /**
     * 处理权限，分层(二级和三级全拼为同一层)
     * @param sysFunctionList
     * @return List<SysFunction>
     */
    public List<SysFunction> handleSysFunction(List<SysFunction> sysFunctionList){
        if(ObjectUtils.isNotEmpty(sysFunctionList)){
            Map<BigDecimal,List<SysFunction>> sysFunctionListMap = sysFunctionList.stream().collect(Collectors.groupingBy(e->e.getParentId()));
            List<SysFunction> parentList = sysFunctionListMap.get(new BigDecimal(0));
            if(ObjectUtils.isNotEmpty(parentList)){
                for(SysFunction parent : parentList){
                    List<SysFunction> childList = new ArrayList<>();
                    recursionSysFunction(childList,parent,sysFunctionListMap);
                    parent.setChildSysFunctionList(childList);
                }
                return parentList;
            }
        }
        return null;
    }
    //递归，把二级和三级的权限放在同一级中
    private void recursionSysFunction(List<SysFunction> childList,SysFunction sysFunction,Map<BigDecimal,List<SysFunction>> sysFunctionListMap){
        if(childList!=null && ObjectUtils.isNotEmpty(sysFunction) && ObjectUtils.isNotEmpty(sysFunctionListMap)){
            List<SysFunction> _childList = sysFunctionListMap.get(sysFunction.getId());
            if(ObjectUtils.isNotEmpty(_childList)){
                childList.addAll(_childList);
                for(SysFunction child : _childList){
                    recursionSysFunction(childList,child,sysFunctionListMap);
                }
            }
        }
    }

    /**
     * 获取用户的权限
     * @param userId 登录的用户的
     * @return 返回用户的权限列表List<SysFunction>
     */
    public List<SysFunction> findUserFunctionList(BigDecimal userId){
        if(userId==null){
            return null;
        }
        //从缓存中获取登录用户的权限列表
        List<SysFunction> sysFunctionList = (List<SysFunction>)customCacheChannel.get(J2CacheRegion.ONE_DAY_REGION.getKey(),CacheConstants.USER_ALL_FUNCTION_LIST_KEY_PREFIX+userId.toString()).getValue();
        if(ObjectUtils.isEmpty(sysFunctionList)){
            sysFunctionList = this.findNotCacheUserFunctionList(userId,false);
            //重新缓存
            customCacheChannel.set(J2CacheRegion.ONE_DAY_REGION.getKey(),CacheConstants.USER_ALL_FUNCTION_LIST_KEY_PREFIX+userId.toString(),sysFunctionList);
        }
        return sysFunctionList;
    }

    /**
     * 查询没有缓存用户的权限
     * @param userId 用户ID
     * @param layered 是否分层
     * @return List<SysFunction>
     */
    public List<SysFunction> findNotCacheUserFunctionList(BigDecimal userId,boolean layered){
        List<SysFunction> userAllFunctionList = new ArrayList<>();
        //查询用户对应角色和部门的权限列表
        List<SysFunction> sysFunctionList = this.findUserRoleAndGroupFunction(userId);
        if(ObjectUtils.isNotEmpty(sysFunctionList)){
            userAllFunctionList.addAll(sysFunctionList);
        }
        //查询用户单独授权的记录
        List<SysUserFunction> sysUserFunctionList = sysUserFunctionBiz.findUserFunctionBuyUserId(userId);
        if(ObjectUtils.isNotEmpty(sysUserFunctionList)){
            String functionIds = sysUserFunctionList.stream().map(e->e.getFunctionId().toString()).collect(Collectors.joining(","));
            List<SysFunction> _sysFunctionList = this.findSysFunctionListByIds(functionIds);
            if(ObjectUtils.isNotEmpty(sysFunctionList)){
                Map<BigDecimal,SysFunction> sysFunctionMap = sysFunctionList.stream().collect(Collectors.toMap(e->e.getId(),e->e));
                _sysFunctionList.forEach(e->{
                    SysFunction sysFunction = sysFunctionMap.get(e.getId());
                    if(sysFunction == null){
                        userAllFunctionList.add(e);
                    }
                });
            }else{
                userAllFunctionList.addAll(_sysFunctionList);
            }
        }
        if(ObjectUtils.isNotEmpty(userAllFunctionList) && layered){
            return this.handleSysFunction(userAllFunctionList);
        }
        return userAllFunctionList;
    }

    /**
     * 获取用户角色和部门的权限
     * @param userId 用户ID
     * @return List<SysFunction>
     */
    public List<SysFunction> findUserRoleAndGroupFunction(BigDecimal userId){
        Set<BigDecimal> functionIdSet = new HashSet<>();
        //用户的所角色
        List<SysRole> sysRoleList = sysUserRoleBiz.findSysUserRoleListByUserId(userId);
        if(ObjectUtils.isNotEmpty(sysRoleList)){
            //得到角色的ID串
            String roleIds = sysRoleList.stream().map(e->e.getId().toString()).collect(Collectors.joining(","));
            //得到角色和资源权限的关联的列表
            List<SysRoleFunction> roleFunctionList = sysRoleFunctionBiz.findSysRoleFunctionListByRoleIds(roleIds);
            if(ObjectUtils.isNotEmpty(roleFunctionList)){
                roleFunctionList.forEach(e->{
                    functionIdSet.add(e.getFunctionId());
                });
            }
        }
        //获取用户部门关联的权限
        List<SysGroupFunction> groupFunctionList = sysGroupFunctionBiz.findUserGroupFunctionList(userId);
        if(ObjectUtils.isNotEmpty(groupFunctionList)){
            groupFunctionList.forEach(e->{
                functionIdSet.add(e.getFunctionId());
            });
        }
        List<SysFunction> sysFunctionList = null;
        if(ObjectUtils.isNotEmpty(functionIdSet)){
            //得到资源权限的ID串
            String functionIds = functionIdSet.stream().map(e->e.toString()).distinct().collect(Collectors.joining(","));
            //查询角色对应的所有的权限列表
            sysFunctionList = this.findSysFunctionListByIds(functionIds);
        }
        return sysFunctionList;
    }




    /**
     * 修改权限节点的父级
     * @param functionId 权限ID
     * @param parentId 新的父级ID
     * @return Map<String,Object>
     */
    public Map<String,Object> updateSysFunctionParent(BigDecimal functionId, BigDecimal parentId) {
        SysFunction sysFunction = new SysFunction();
        sysFunction.setParentId(parentId);
        this.updateByWhereSql(sysFunction," id = "+ functionId);
        return ResultUtil.SUCCESS("权限父级节点修改成功");
    }


    /**
     * 查询所有的权限（分3层）
     * @return List<SysFunction>
     */
    private List<SysFunction> scaleFunctionList(List<SysFunction> sysFunctionList){
        if(ObjectUtils.isNotEmpty(sysFunctionList)){
            Map<BigDecimal,List<SysFunction>> sysFunctionListMap = sysFunctionList.stream().collect(Collectors.groupingBy(e->e.getParentId()));
           //获取一级的权限
            List<SysFunction> parentList = sysFunctionListMap.get(BigDecimal.ZERO);
            //一级

            if(ObjectUtils.isNotEmpty(parentList)){
                parentList.forEach(parent ->{
                    //二级
                    List<SysFunction> childFunctionList = sysFunctionListMap.get(parent.getId());
                    if(ObjectUtils.isNotEmpty(childFunctionList)){
                        //合并4级到3级中
                        childFunctionList.forEach(c->{
                            List<SysFunction> _childList = sysFunctionListMap.get(c.getId());
                            if(ObjectUtils.isNotEmpty(_childList)){
                                List<SysFunction> resultList = new ArrayList<>();
                                getFunctionAllChildNode(resultList,_childList,sysFunctionListMap);
                                //把合并后3级设置到2级下面
                                c.setChildSysFunctionList(resultList);
                            }
                        });
                        //把二级设置到一级的下面
                        parent.setChildSysFunctionList(childFunctionList);
                    }
                });
                return parentList;
            }
        }
        return null;
    }

    /**
     * 获取权限的所有的子级权限数据
     * @param resultList 所有子权限数据列表
     * @param childFunctionList 子权限列表
     * @param sysFunctionListMap 所有的权限Map
     */
    private void getFunctionAllChildNode(List<SysFunction> resultList,List<SysFunction> childFunctionList, Map<BigDecimal,List<SysFunction>> sysFunctionListMap){
        childFunctionList.forEach(c->{
            resultList.add(c);
            List<SysFunction> _childList = sysFunctionListMap.get(c.getId());
            if(ObjectUtils.isNotEmpty(_childList)){
               // resultList.addAll(_childList);
                getFunctionAllChildNode(resultList,_childList,sysFunctionListMap);
            }
        });
    }
}
